3. Shape Manipulation
==================

3.1 Changing the shape of an array
------------------------------

An array has a shape given by the number of elements along each axis:

>>> a = np.floor(10*np.random.random((3,4)))
>>> a
array([[ 2.,  8.,  0.,  6.],
[ 4.,  5.,  1.,  1.],
[ 8.,  9.,  3.,  6.]])
>>> a.shape
(3, 4)

The shape of an array can be changed with various commands:

>>> a.ravel() # flatten the array
array([ 2.,  8.,  0.,  6.,  4.,  5.,  1.,  1.,  8.,  9.,  3.,  6.])
>>> a.shape = (6, 2)
>>> a.T
array([[ 2.,  0.,  4.,  1.,  8.,  3.],
[ 8.,  6.,  5.,  1.,  9.,  6.]])

[demo]

import numpy as np
a = np.floor(10*np.random.random((3,4)))
print(a)
print(a.shape)
print(a.ravel())
a.shape = (6, 2)
print(a.T)
print(a)
a.resize((2,6))
print(a)
print(a.reshape(3,-1))


[/demo]


The order of the elements in the array resulting from ravel() is
normally "C-style", that is, the rightmost index "changes the fastest",
so the element after a[0,0] is a[0,1]. If the array is reshaped to some
other shape, again the array is treated as "C-style". Numpy normally
creates arrays stored in this order, so ravel() will usually not need to
copy its argument, but if the array was made by taking slices of another
array or created with unusual options, it may need to be copied. The
functions ravel() and reshape() can also be instructed, using an
optional argument, to use FORTRAN-style arrays, in which the leftmost
index changes the fastest.

The `reshape` function returns its
argument with a modified shape, whereas the
`ndarray.resize` method modifies the array
itself:

>>> a
array([[ 2.,  8.],
[ 0.,  6.],
[ 4.,  5.],
[ 1.,  1.],
[ 8.,  9.],
[ 3.,  6.]])
>>> a.resize((2,6))
>>> a
array([[ 2.,  8.,  0.,  6.,  4.,  5.],
[ 1.,  1.,  8.,  9.,  3.,  6.]])

If a dimension is given as -1 in a reshaping operation, the other
dimensions are automatically calculated:

>>> a.reshape(3,-1)
array([[ 2.,  8.,  0.,  6.],
[ 4.,  5.,  1.,  1.],
[ 8.,  9.,  3.,  6.]])

.. seealso::

`ndarray.shape`,
`reshape`,
`resize`,
`ravel`

3.2 Stacking together different arrays
----------------------------------

Several arrays can be stacked together along different axes:

>>> a = np.floor(10*np.random.random((2,2)))
>>> a
array([[ 8.,  8.],
[ 0.,  0.]])
>>> b = np.floor(10*np.random.random((2,2)))
>>> b
array([[ 1.,  8.],
[ 0.,  4.]])
>>> np.vstack((a,b))
array([[ 8.,  8.],
[ 0.,  0.],
[ 1.,  8.],
[ 0.,  4.]])
>>> np.hstack((a,b))
array([[ 8.,  8.,  1.,  8.],
[ 0.,  0.,  0.,  4.]])

[demo]

import numpy as np
a = np.floor(10*np.random.random((2,2)))
print(a)
b = np.floor(10*np.random.random((2,2)))
print(b)
print(np.vstack((a,b)))
print(np.hstack((a,b)))

[/demo]


The function `column_stack`
stacks 1D arrays as columns into a 2D array. It is equivalent to
`vstack` only for 1D arrays:

>>> from numpy import newaxis
>>> np.column_stack((a,b))   # With 2D arrays
array([[ 8.,  8.,  1.,  8.],
[ 0.,  0.,  0.,  4.]])
>>> a = np.array([4.,2.])
>>> b = np.array([2.,8.])
>>> a[:,newaxis]  # This allows to have a 2D columns vector
array([[ 4.],
[ 2.]])
>>> np.column_stack((a[:,newaxis],b[:,newaxis]))
array([[ 4.,  2.],
[ 2.,  8.]])
>>> np.vstack((a[:,newaxis],b[:,newaxis])) # The behavior of vstack is different
array([[ 4.],
[ 2.],
[ 2.],
[ 8.]])

[demo]

import numpy as np
from numpy import newaxis
print(np.column_stack((a,b)))
a = np.array([4.,2.])
b = np.array([2.,8.])
print(a[:,newaxis])
print(np.column_stack((a[:,newaxis],b[:,newaxis])))
print(np.vstack((a[:,newaxis],b[:,newaxis])))
print(np.r_[1:4,0,4])

[/demo]


For arrays of with more than two dimensions,
`hstack` stacks along their second
axes, `vstack` stacks along their
first axes, and `concatenate`
allows for an optional arguments giving the number of the axis along
which the concatenation should happen.

**Note**

In complex cases, `r_` and
`c_` are useful for creating arrays
by stacking numbers along one axis. They allow the use of range literals
(":") :

>>> np.r_[1:4,0,4]
array([1, 2, 3, 0, 4])

When used with arrays as arguments,
`r_` and
`c_` are similar to
`vstack` and
`hstack` in their default behavior,
but allow for an optional argument giving the number of the axis along
which to concatenate.

.. seealso::

`hstack`,
`vstack`,
`column_stack`,
`concatenate`,
`c_`,
`r_`

3.3 Splitting one array into several smaller ones
---------------------------------------------

Using `hsplit`, you can split an
array along its horizontal axis, either by specifying the number of
equally shaped arrays to return, or by specifying the columns after
which the division should occur:

>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[ 9.,  5.,  6.,  3.,  6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],
[ 1.,  4.,  9.,  2.,  2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])
>>> np.hsplit(a,3)   # Split a into 3
[array([[ 9.,  5.,  6.,  3.],
[ 1.,  4.,  9.,  2.]]), array([[ 6.,  8.,  0.,  7.],
[ 2.,  1.,  0.,  6.]]), array([[ 9.,  7.,  2.,  7.],
[ 2.,  2.,  4.,  0.]])]
>>> np.hsplit(a,(3,4))   # Split a after the third and the fourth column
[array([[ 9.,  5.,  6.],
[ 1.,  4.,  9.]]), array([[ 3.],
[ 2.]]), array([[ 6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],
[ 2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])]

[demo]

import numpy as np
a = np.floor(10*np.random.random((2,12)))
print(a)
print(np.hsplit(a,3))
print(np.hsplit(a,(3,4)))

[/demo]


`vsplit` splits along the vertical
axis, and `array_split` allows
one to specify along which axis to split.